/**
 * 
 */
package com.toncen.samepms.common;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.struts2.ServletActionContext;

import com.toncen.samepms.interceptor.In;
import com.toncen.samepms.interceptor.Out;
import com.toncen.samepms.interceptor.SessionScopeInterceptor;
import com.sky.common.clone.CloneUtils;
import com.sky.common.string.StringUtils;

/**
 * 描述：一对多内存操作Action基类
 * 
 * @author tch
 */
public abstract class AbstractMemoryAction<M extends IDomain> extends AbstractAction<M> implements IMemoryActionable<M> {
	/**
	 * 主domain的Action的类全名
	 */
	@In
	@Out
	private String actionName;

	/**
	 * 主domain在内存中的属性名
	 */
	@In
	@Out
	private String attributeName = "domain";

	/**
	 * 主domain中从表的属性名
	 */
	@In
	@Out
	private String manyPropertyName;

	/**
	 * 从表中主domain的属性名
	 */
	@In
	@Out
	private String onePropertyName;

	/**
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public AbstractMemoryAction() throws Exception {
		super();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#delete(long)
	 */
	public void delete(long domainId) throws Exception {
		for (M domain : getManyDomainList()) {
			if (domain.getId() == domainId) {
				getManyDomainList().remove(domain);
				break;
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#load(long)
	 */
	@SuppressWarnings("unchecked")
	public M load(long domainId) throws Exception {
		M domain = null;
		for (M d : getManyDomainList()) {
			if (d.getId() == domainId) {
				domain = (M) CloneUtils.deepClone(d);
				break;
			}
		}
		return domain;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#save(com.toncen.samepms.common.AbstractDomain)
	 */
	public void save(M domain) throws Exception {
		M oldDomain = load(domain.getId());
		if (domain.isSaved() && oldDomain != null) {// 已经持久化，则修改
			delete(domain.getId());// 删除原有的
			getManyDomainList().add(domain);
		} else {// 新增
			if(!domain.isSaved()){//未保存，则创建主键
				domain.setId(getPrimaryID());// 设置主键
			}
			PropertyUtils.setProperty(domain, getOnePropertyName(), getOneDomain());// 把主表设置到从表中
			getManyDomainList().add(domain);
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.AbstractAction#find(long)
	 */
	public M find(long domainId) throws Exception {
		return load(domainId);
	}

	/**
	 * 获取从表domain列表
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected List<M> getManyDomainList() throws Exception {
		Object domain = getOneDomain();
		Object property = getDataMany(ServletActionContext.getRequest(), getActionName(), getAttributeName(), getManyPropertyName(), getOnePropertyName());
		if (!(property instanceof List)) {
			throw new IllegalArgumentException("当前会话中属性名称为【" + actionName + "】的属性【" + attributeName + "】数据【" + domain.getClass().getName() + "】的属性【"
					+ manyPropertyName + "】数值类型【" + property.getClass().getName() + "】不属于类型【" + List.class.getName() + "】，请与系统管理员联系！");
		}
		return (List<M>) property;
	}

	/**
	 * 获取从表domain
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	protected M getManyDomain() throws Exception {
		return (M) getDataMany(ServletActionContext.getRequest(), getActionName(), getAttributeName(), getManyPropertyName(), getOnePropertyName());
	}

	/**
	 * 获取主表domain
	 * 
	 * @return
	 * @throws Exception
	 */
	protected Object getOneDomain() throws Exception {
		return getDataOne(ServletActionContext.getRequest(), getActionName(), getAttributeName(), getManyPropertyName(), getOnePropertyName());
	}

	/**
	 * 获取主表domain
	 * 
	 * @param request
	 * @param actionName
	 * @param attributeName
	 * @param manyPropertyName
	 * @param onePropertyName
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static Object getDataOne(HttpServletRequest request, String actionName, String attributeName, String manyPropertyName, String onePropertyName)
			throws Exception {
		if (StringUtils.isEmpty(actionName)) {
			throw new IllegalArgumentException("未设置Action名称【actionName】，请与系统管理员联系！");
		}
		if (StringUtils.isEmpty(attributeName)) {
			throw new IllegalArgumentException("未设置Attribute名称【attributeName】，请与系统管理员联系！");
		}
		if (StringUtils.isEmpty(manyPropertyName)) {
			throw new IllegalArgumentException("未设置Property名称【manyPropertyName】，请与系统管理员联系！");
		}
		if (StringUtils.isEmpty(onePropertyName)) {
			throw new IllegalArgumentException("未设置Property名称【onePropertyName】，请与系统管理员联系！");
		}
		// session中的数据
		Object data = request.getSession().getAttribute(SessionScopeInterceptor.getSessionAttributeName(actionName));
		if (data == null) {
			throw new IllegalArgumentException("当前会话中未找到属性名称为【" + actionName + "】的数据，请与系统管理员联系！");
		}
		if (!(data instanceof Map)) {
			throw new IllegalArgumentException("当前会话中属性名称为【" + actionName + "】的【" + data.getClass().getName() + "】没有继承【" + Map.class.getName() + "】，请与系统管理员联系！");
		}
		// 主表domain
		Object domain = ((HashMap) data).get(attributeName);
		if (domain == null) {
			throw new IllegalArgumentException("当前会话中属性名称为【" + actionName + "】的属性【" + attributeName + "】数据未找到，请与系统管理员联系！");
		}
		if (!(domain instanceof AbstractDomain)) {
			throw new IllegalArgumentException("当前会话中属性名称为【" + actionName + "】的属性【" + attributeName + "】数据【" + domain.getClass().getName() + "】没有继承【"
					+ AbstractDomain.class.getName() + "】，请与系统管理员联系！");
		}
		return domain;
	}

	/**
	 * 获取从表domain列表
	 * 
	 * @param request
	 * @param actionName
	 * @param attributeName
	 * @param manyPropertyName
	 * @param onePropertyName
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public static Object getDataMany(HttpServletRequest request, String actionName, String attributeName, String manyPropertyName, String onePropertyName)
			throws Exception {
		Object domain = getDataOne(request, actionName, attributeName, manyPropertyName, onePropertyName);
		// 从表property
		Object property = PropertyUtils.getProperty(domain, manyPropertyName);
		if (property == null) {
			throw new IllegalArgumentException("当前会话中属性名称为【" + actionName + "】的属性【" + attributeName + "】数据【" + domain.getClass().getName() + "】的属性【"
					+ manyPropertyName + "】数值不存在，请与系统管理员联系！");
		}
		return property;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#getActionName()
	 */
	public String getActionName() {
		return actionName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#setActionName(java.lang.String)
	 */
	public void setActionName(String actionName) {
		this.actionName = actionName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#getAttributeName()
	 */
	public String getAttributeName() {
		return attributeName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#setAttributeName(java.lang.String)
	 */
	public void setAttributeName(String domainName) {
		this.attributeName = domainName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#getManyPropertyName()
	 */
	public String getManyPropertyName() {
		return manyPropertyName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#setManyPropertyName(java.lang.String)
	 */
	public void setManyPropertyName(String manyPropertyName) {
		this.manyPropertyName = manyPropertyName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#getOnePropertyName()
	 */
	public String getOnePropertyName() {
		return onePropertyName;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.toncen.samepms.common.IMemoryActionable#setOnePropertyName(java.lang.String)
	 */
	public void setOnePropertyName(String onePropertyName) {
		this.onePropertyName = onePropertyName;
	}

}
